import { put, takeLatest } from 'redux-saga/effects'

import { changeLngLat, safeJsonParse } from '@/utils/util'
import call from '../call'
import { DATACENTER } from '../actionTypes'
import {
  updateCityInfo,
  updateAreaInfo,
  updateBikeInfo,
  updateHeatMapInfo,
  updateOperationInfo,
  updateSearchBikeInfo,
  updateParkingAreaInfo,
  updateSearchOperationInfo,
  updateBufferParkingAreaInfo,
  updateSearchParkingAreaInfo,
  updateSearchBufferParkingAreaInfo,
  updateKeyAreaInfo,
  updateSearchKeyAreaInfo,
  updateCameraInfo,
  updateSniffHeatMapInfo,
} from '../reducers/dataCenter'

import {
  queryHeatMap as queryHeatMapService,
  querySniffHeatMap as querySniffHeatMapService,
  queryCityInfo as queryCityInfoService,
  queryBikeInfo as queryBikeInfoService,
  queryAreaRegion as queryAreaRegionService,
  querySearchBike as querySearchBikeService,
  queryOperationInfo as queryOperationInfoService,
  querySubwayBikeInfo as querySubwayBikeInfoService,
  queryParkingAreaInfo as queryParkingAreaInfoService,
  querySearchParkingArea as querySearchParkingAreaService,
  querySearchOperationInfo as querySearchOperationInfoService,
  queryKeyAreaInfo as queryKeyAreaInfoService,
  queryCameraInfo as queryCameraInfoService,
} from '../service/dataCenter'

function* queryCityInfo(action: Action) {
  const res: ResponseData = yield call(queryCityInfoService, action)
  if (res?.code === 0 && res.data) {
    yield put(updateCityInfo(res.data))
  }
}

function* queryBikeInfo(action: Action) {
  const res: ResponseData = yield call(queryBikeInfoService, action)
  if (res.code === 0 && res.data) {
    const data = res.data || []
    const [bikeLocations = [], spockLocations = []] = [
      data.bike?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
      data.spock?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
    ]
    yield put(updateBikeInfo({ bikeLocations, spockLocations }))
    // 使用bikeId搜索
    // if (action.payload?.bikeId && bikeLocations.length && action.cb) {
    //   action.cb(bikeLocations[0])
    // }
  }
}

function* querySubwayBikeInfo(action: Action) {
  const res: ResponseData = yield call(querySubwayBikeInfoService, action)
  if (res.code === 0 && res.data) {
    const data = res.data || []
    const [bikeLocations = [], spockLocations = []] = [
      data.bike?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
      data.spock?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
    ]
    yield put(updateBikeInfo({ bikeLocations, spockLocations }))
  }
}

function* queryAreaRegion(action: Action) {
  const res: ResponseData = yield call(queryAreaRegionService, action)
  if (res?.code === 0 && res.data) {
    const { center = [], region = {} } = res.data
    const areaInfo = { region: changeLngLat(region.coordinates), center }
    yield put(updateAreaInfo(areaInfo))
  }
}

function* querySearchBike(action: Action) {
  const res: ResponseData = yield call(querySearchBikeService, action)
  if (res?.code === 0 && res.data) {
    const data = res.data
    const [bikeLocations = [], spockLocations = []] = [
      [data].map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        isSearched: true,
        ...info,
      })),
    ]
    yield put(updateSearchBikeInfo({ bikeLocations, spockLocations }))
    if (bikeLocations.length && action.cb) {
      action.cb(bikeLocations[0])
    }
  } else if (res?.code === 0 && !res.data) {
    action.cb?.(res.data)
  }
}

function* queryParkingAreaInfo(action: Action) {
  const res: ResponseData = yield call(queryParkingAreaInfoService, action)
  if (res?.code === 0 && res.data) {
    const { parkingArea } = action.extra || {}
    const parkingLocationInfo = res.data.parkingLocationInfo || []
    const bufferCoordinates: any = []
    const coordinates = parkingLocationInfo.map((position: any) => {
      if (position.depositBufferGeoJson) {
        const region = safeJsonParse(position['depositBufferGeoJson'])
        bufferCoordinates.push({
          ...position,
          region: changeLngLat(region.coordinates),
        })
      }
      const region = safeJsonParse(position['region'])
      return {
        ...position,
        rawRegion: region,
        isEdit: parkingArea?.fencingId === position.fencingId,
        region: changeLngLat(region.coordinates),
      }
    })
    yield put(updateParkingAreaInfo(coordinates))
    yield put(updateBufferParkingAreaInfo(bufferCoordinates))
  }
}

function* querySearchParkingArea(action: Action) {
  const res: ResponseData = yield call(querySearchParkingAreaService, action)
  if (res?.code === 0 && res.data) {
    const { parkingArea } = action.extra || {}
    const parkingLocationInfo = res.data || []
    const searchBufferCoordinates: any = []
    const coordinates = [parkingLocationInfo].map((position: any) => {
      if (position.depositBufferGeoJson) {
        const region = safeJsonParse(position['depositBufferGeoJson'])
        searchBufferCoordinates.push({
          ...position,
          region: changeLngLat(region.coordinates),
        })
      }
      const region = safeJsonParse(position['region'])
      return {
        ...position,
        rawRegion: region,
        isEdit: parkingArea?.fencingId === position.fencingId,
        isSearched: true,
        region: changeLngLat(region.coordinates),
      }
    })
    if (parkingLocationInfo && action.cb) {
      action.cb(parkingLocationInfo)
    }
    yield put(updateSearchParkingAreaInfo(coordinates))
    yield put(updateSearchBufferParkingAreaInfo(searchBufferCoordinates))
  } else if (res?.code === 0 && !res.data) {
    action.cb?.(res.data)
  }
}

function* queryHeatMap(action: Action) {
  const res: ResponseData = yield call(queryHeatMapService, action)
  if (res && res.code === 0) {
    const data = res.data || []
    const [bikeLocations = [], spockLocations = []] = [
      data.bike?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
      data.spock?.bikeLocationInfo?.map((info: any) => ({
        lat: +info.bikeReportLngLat[1],
        lng: +info.bikeReportLngLat[0],
        ...info,
      })),
    ]
    yield put(updateHeatMapInfo({ bikeLocations, spockLocations }))
  }
}

function* querySniffHeatMap(action: Action) {
  const res: ResponseData = yield call(querySniffHeatMapService, action)
  if (res && res.code === 0) {
    const data = res.data || []
    yield put(updateSniffHeatMapInfo(data))
  }
}

function* queryOperationInfo(action: Action) {
  const res: ResponseData = yield call(queryOperationInfoService, action)
  if (res?.code === 0 && res.data) {
    yield put(updateOperationInfo(res.data))
  }
}

function* querySearchOperationInfo(action: Action) {
  const res: ResponseData = yield call(querySearchOperationInfoService, action)
  if (res?.code === 0 && res.data) {
    yield put(updateSearchOperationInfo(res.data))
  }
  action.cb?.(res.data)
}

function* queryKeyAreaInfo(action: Action) {
  if (action.payload?.clear) {
    yield put(updateKeyAreaInfo([]))
    return
  }
  const res: ResponseData = yield call(queryKeyAreaInfoService, action)
  if (res.code === 0 && res.data) {
    const keyAreaInfo = res.data || []
    const coordinates = keyAreaInfo.map((position: any) => {
      const region = safeJsonParse(position['fencingGeoJson'])
      return {
        ...position,
        rawRegion: region,
        region: changeLngLat(region.coordinates),
        isSearched: position.fencingId === action.payload?.searchString,
      }
    })
    if (action.payload?.searchString) {
      yield put(updateSearchKeyAreaInfo(coordinates))
      yield action.cb?.(coordinates)
    } else {
      yield put(updateKeyAreaInfo(coordinates))
    }
  }
}

function* queryCameraInfo(action: Action) {
  if (action.payload?.clear) {
    yield put(updateCameraInfo([]))
    return
  }
  const res: ResponseData = yield call(queryCameraInfoService, action)
  if (res.code === 0 && res.data) {
    yield put(updateCameraInfo(res.data))
  }
}

export default function* root() {
  yield takeLatest(DATACENTER.QUERY_CITY_INFO, queryCityInfo)
  yield takeLatest(DATACENTER.QUERY_AREA_REGION, queryAreaRegion)
  yield takeLatest(DATACENTER.QUERY_BIKE_INFO, queryBikeInfo)
  yield takeLatest(DATACENTER.QUERY_HEAT_MAP, queryHeatMap)
  yield takeLatest(DATACENTER.QUERY_SNIFF_HEAT_MAP, querySniffHeatMap)
  yield takeLatest(DATACENTER.QUERY_SEARCH_BIKE, querySearchBike)
  yield takeLatest(DATACENTER.QUERY_PARKING_AREA_INFO, queryParkingAreaInfo)
  yield takeLatest(DATACENTER.QUERY_SEARCH_PARKING_AREA, querySearchParkingArea)
  yield takeLatest(DATACENTER.QUERY_SUBWAY_BIKE_INFO, querySubwayBikeInfo)
  yield takeLatest(DATACENTER.QUERY_OPERATION_INFO, queryOperationInfo)
  yield takeLatest(DATACENTER.QUERY_SEARCH_OPERATION_INFO, querySearchOperationInfo)
  yield takeLatest(DATACENTER.QUERY_KEY_AREA_INFO, queryKeyAreaInfo)
  yield takeLatest(DATACENTER.QUERY_CAMERA_INFO, queryCameraInfo)
}
